export var CanvasLabelType;
(function (CanvasLabelType) {
    CanvasLabelType["BOX"] = "box";
    CanvasLabelType["Polygon"] = "polygon";
})(CanvasLabelType || (CanvasLabelType = {}));
export var CanvasEventType;
(function (CanvasEventType) {
    CanvasEventType["CheckType"] = "checkType";
    CanvasEventType["DrawEnd"] = "drawEnd";
    CanvasEventType["Hover"] = "hover";
    CanvasEventType["Scale"] = "scale";
    CanvasEventType["Translate"] = "translate";
    CanvasEventType["CheckLabelType"] = "checkLabelType";
    CanvasEventType["Select"] = "select";
    CanvasEventType["NewLabel"] = "newLabel";
    CanvasEventType["Change"] = "change";
})(CanvasEventType || (CanvasEventType = {}));
// 操作类型
export var OpType;
(function (OpType) {
    OpType[OpType["CanvasLabelType"] = 0] = "CanvasLabelType";
    OpType["None"] = "none";
    OpType["Select"] = "select";
    OpType["Move"] = "move";
})(OpType || (OpType = {}));
function deepCopy(data) {
    return JSON.parse(JSON.stringify(data));
}
/**
 * 旧数据对于新数中的数据 在新数据中有的 拿过来 没有的保留
 * @param o 原本数据
 * @param n 新数据
 * @returns 返回覆盖后的数据
 */
export function coverData(o, n) {
    // 新数据
    let r1 = Object.entries(n);
    r1.forEach((data) => {
        if (typeof data[1] == 'undefined') {
            return;
        }
        if (Array.isArray(data[1]) || data[1] instanceof Map || typeof data[1] != 'object') {
            Object.defineProperty(o, data[0], {
                value: data[1]
            });
            return;
        }
        return coverData(o[data[0]], data[1]);
    });
    return o;
}
// 创建map数据
export function createMapData(data, type) {
    let map = new Map();
    for (let i of data) {
        if (type == 'label') {
            i.hidden = false;
            i.select = false;
        }
        else if (type == 'type') {
            i.hidden = false;
            i.use = true;
        }
        map.set(i.id, i);
    }
    return map;
}
// 获取标签数据
function getLabelData(l) {
    if (l.type === CanvasLabelType.BOX) {
        return [
            l.data[0], l.data[1],
            l.data[0] + l.data[2], l.data[1],
            l.data[0] + l.data[2], l.data[1] + l.data[3],
            l.data[0], l.data[1] + l.data[3]
        ];
    }
    else if (l.type === CanvasLabelType.Polygon) {
        return deepCopy(l.data);
    }
    return [];
}
// 返回缩放信息
function copyBD(b) {
    return {
        mx: b.mx,
        my: b.my,
        zoom: b.zoom
    };
}
export class CanvasLabel {
    // 容器元素
    #el = null;
    // 2d上下文
    #ctx = null;
    // 画布元素
    #canvas = null;
    // dom大小变化监听器
    #resizeOB = null;
    // 背景图片
    #backData = null;
    #setting = {
        background: '#bcffc3',
        showLabelTagType: "name",
        labelTypeList: new Map(),
        sightBead: {
            coordinatesColor: "#888",
            coordinatesWidth: 2,
            fontColor: '#ff6',
            fontStyle: '10px "微软雅黑"'
        },
        selectStyle: {
            strokeStyle: "rgba(200,0,0,0.8)",
            strokeWidth: 6,
            fillStyle: "rgba(122,0,0,.4)",
            pointFillR: 6,
            pointFillStyle: "rgba(0,230,25,.9)"
        },
        selectIngStyle: {
            strokeStyle: "rgba(100,60,0,0.8)",
            strokeWidth: 6,
            fillStyle: "rgba(200,200,0,.4)"
        },
        offKbdEvent: false
    };
    #store = {
        mouseIsDown: false,
        x: 0,
        y: 0,
        cx: 0,
        cy: 0,
        oldOpType: OpType.None,
        // hiddenLabelTypeIds: [],
        hiddenLabelIds: [],
        // useLabelTypeIds: []
    };
    /**
     *
     */
    #opType = OpType.None;
    // 所有标签数据
    #labelList = new Map();
    /**
     * 被选择的标签列表
     */
    #selectLabelIds = [];
    /**
     * 正在标注的数据
     */
    #labelIngData = null;
    #eventFun = () => { };
    constructor(el, watchResize) {
        this.#el = document.querySelector(el);
        let canvas = document.createElement('canvas');
        canvas.innerHTML = '你的浏览器不支持canvas';
        canvas.style.userSelect = 'none';
        this.#ctx = canvas.getContext('2d');
        this.#canvas = canvas;
        // 隐藏鼠标
        canvas.style.cursor = "none";
        this.#el?.appendChild(canvas);
        // 调整窗口大小
        if (this.#el) {
            if (watchResize) {
                let resizeob = new ResizeObserver(() => {
                    this.reSize();
                });
                this.#resizeOB = resizeob;
                resizeob.observe(this.#el);
            }
            else {
                this.reSize();
            }
        }
        this.setSetting();
        this.#onEvent();
    }
    /**
     * 重置画布大小
     * @param w
     * @param h
     */
    reSize(w, h) {
        if (this.#canvas && this.#el) {
            if (w !== undefined && h !== undefined) {
                this.#canvas.width = w;
                this.#canvas.height = h;
            }
            else {
                this.#canvas.width = this.#el.clientWidth;
                this.#canvas.height = this.#el.clientHeight;
            }
        }
        this.#drawPipeLine();
    }
    /**
     * 重绘
     */
    reDraw() {
        this.#drawPipeLine();
    }
    /**
     * 删除标签
     * @param id 标签id
     */
    delLabel(id) {
        const fun = (id) => {
            this.#labelList.delete(id);
            this.#drawPipeLine();
            this.#eventFun({ type: CanvasEventType.Change, data: null });
        };
        if (Array.isArray(id)) {
            id.forEach((d) => {
                fun(d);
            });
        }
        else if (typeof id === 'number') {
            fun(id);
        }
        // this.#drawLocation()
    }
    /**
     * 添加设置
     * @param st 设置
     */
    setSetting(st = {}) {
        this.#setting = coverData(this.#setting, st);
        this.#drawPipeLine();
    }
    /**
     * 获取设置
     */
    getSetting() {
        return this.#setting;
    }
    /**
     * 使用某个标签
     * @param id
     */
    useLabelType(ids) {
        // this.#store.useLabelTypeIds = ids
        for (let id of ids) {
            let type = this.#setting.labelTypeList?.get(id);
            if (!type) {
                break;
            }
            if (type.use) {
                type.use = false;
            }
            else {
                type.use = true;
            }
        }
        this.#eventFun({ type: CanvasEventType.CheckLabelType, data: this.#setting.labelTypeList });
    }
    /**
     * 监听所有事件
     * @param cbk 回调函数
     */
    onEvent(cbk) {
        this.#eventFun = cbk;
    }
    /**
     * 移除事件监听
     */
    offEvent() {
        this.#eventFun = () => { };
    }
    /**
     * 设置需要隐藏的标签列表
     * @param id
     */
    hiddenLabels(ids) {
        this.#store.hiddenLabelIds = ids;
        for (let id of ids) {
            let label = this.#labelList.get(id);
            if (!label) {
                break;
            }
            label.hidden = true;
        }
        this.#drawPipeLine();
    }
    /**
     * 删除被隐藏的标签列表中的某个标签
     * @param id
     */
    showLabel(id) {
        let index = this.#store.hiddenLabelIds.indexOf(id);
        this.#store.hiddenLabelIds.splice(index, 1);
        let label = this.#labelList.get(id);
        if (label) {
            label.hidden = false;
        }
        this.#drawPipeLine();
    }
    /**
     * 添加需要隐藏的标签
     * @param id
     */
    hiddenLabel(id) {
        this.#store.hiddenLabelIds.push(id);
        let label = this.#labelList.get(id);
        if (label) {
            label.hidden = true;
        }
        this.#drawPipeLine();
    }
    /**
     * 切换标签的 显示状态
     * @param id
     */
    labelDisplay(id) {
        if (this.labelIsHidden(id)) {
            this.showLabel(id);
        }
        else {
            this.hiddenLabel(id);
        }
    }
    /**
     * 设置需要隐藏的标签类型列表
     * @param id
     */
    hiddenLabelTypes(ids) {
        // this.#store.hiddenLabelTypeIds = ids
        for (let id of ids) {
            let type = this.#setting.labelTypeList?.get(id);
            if (!type) {
                break;
            }
            type.hidden = true;
        }
        this.#drawPipeLine();
    }
    /**
     * 删除需要已经隐藏的标签类型
     * @param id
     */
    showLabelType(id) {
        // let i = this.#store.hiddenLabelTypeIds.indexOf(id)
        // this.#store.hiddenLabelTypeIds.splice(i, 1)
        let type = this.#setting.labelTypeList?.get(id);
        if (type) {
            type.hidden = false;
        }
        this.#drawPipeLine();
    }
    /**
     * 添加需要隐藏的标签类型
     * @param id
     */
    hiddenLabelType(id) {
        // this.#store.hiddenLabelTypeIds.push(id)
        let type = this.#setting.labelTypeList?.get(id);
        if (type) {
            type.hidden = true;
        }
        this.#drawPipeLine();
    }
    /**
     * 切换标签类型的显示状态
     * @param id
     */
    labelTypeDisplay(id) {
        if (this.labelTypeIsHidden(id)) {
            this.showLabelType(id);
        }
        else {
            this.hiddenLabelType(id);
        }
    }
    /**
     * 检查某个标签是否被隐藏
     * @param id
     * @returns
     */
    labelIsHidden(id) {
        let label = this.#labelList.get(id);
        if (label) {
            return label.hidden;
        }
        return this.#store.hiddenLabelIds.indexOf(id) >= 0;
    }
    /**
     * 检查某个标签类型是否被隐藏
     * @param id
     * @returns
     */
    labelTypeIsHidden(id) {
        let type = this.#setting.labelTypeList?.get(id);
        if (type) {
            return type.hidden;
        }
        return false;
        // return this.#store.hiddenLabelTypeIds.indexOf(id) >= 0
    }
    /**
     * 检查标签类型是否正在使用
     * @param id type id
     * @returns 返回 标签类型的使用状态
     */
    labelTypeIsUse(id) {
        let type = this.#setting.labelTypeList?.get(id);
        if (type) {
            return type.use;
        }
        // return this.#store.useLabelTypeIds.indexOf(id) >= 0
        return false;
    }
    /**
     * 绘制管线
     * 首先绘制 背景图片
     * 然后依次按照顺序绘制各个 标签
     */
    #drawPipeLine() {
        if (this.#ctx && this.#canvas) {
            let ctx = this.#ctx;
            let cvs = this.#canvas;
            ctx.save();
            this.clear();
            // 绘制背景颜色
            ctx.fillStyle = this.#setting?.background || '#fff';
            ctx.fillRect(0, 0, cvs.width, cvs.height);
            ctx.restore();
            ctx.save();
            if (this.#backData) {
                let d = this.#backData;
                ctx.transform(d.zoom, 0, 0, d.zoom, d.mx, d.my);
                ctx.drawImage(d.data, 0, 0, d.w, d.h);
                let line = this.#labelList;
                let index = 0;
                line.forEach((item) => {
                    this.#drawLabel(item, index + 1);
                    index++;
                });
                // 绘制正在绘制的 数据
                let labeling = this.#labelIngData;
                if (labeling) {
                    this.#drawLabel(labeling, 0);
                }
            }
            this.#drawPoint();
            ctx.restore();
        }
        this.#eventFun({ type: CanvasEventType.DrawEnd, data: this.#labelList });
    }
    /* 获取绘制上下文 */
    getCtx() {
        return this.#ctx;
    }
    /**
     * 清除指定区域的绘制 如果不传入值的话 就会清除整canvas
     * @param x 坐标
     * @param y 坐标
     * @param w 宽
     * @param h 长
     */
    clear(x, y, w, h) {
        if (!this.#ctx || !this.#canvas) {
            return;
        }
        if (x !== undefined && y !== undefined && w !== undefined && h !== undefined) {
            this.#ctx.clearRect(x, y, w, h);
        }
        else {
            this.#ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height);
        }
    }
    /**
     * 注册所有的事件
     */
    #onEvent() {
        if (!this.#canvas || !this.#ctx) {
            return;
        }
        const cvs = this.#canvas;
        let that = this;
        function saveMouseP(e) {
            if (!that.#backData) {
                return;
            }
            // 鼠标坐标 
            let x = e.offsetX;
            let y = e.offsetY;
            that.#store.x = x;
            that.#store.y = y;
            let bd = that.#backData;
            // 鼠标坐标 缩放过后再图片上的坐标
            that.#store.cx = (x - bd.mx) / bd.zoom;
            that.#store.cy = (y - bd.my) / bd.zoom;
            let eve = {
                cx: that.#store.cx,
                cy: that.#store.cy,
                x: that.#store.x,
                y: that.#store.y
            };
            that.#eventFun({ type: CanvasEventType.Hover, data: eve });
        }
        cvs.addEventListener('wheel', (e) => {
            e.preventDefault();
            if (!this.#canvas || !this.#backData) {
                return;
            }
            let x = e.offsetX;
            let y = e.offsetY;
            if (e.altKey) {
                // 水平移动
                e.deltaY < 0 ? this.translate(20) : this.translate(-20);
            }
            else if (e.ctrlKey) {
                // 缩放
                e.deltaY < 0 ? this.scale(0.1, x, y) : this.scale(-0.1, x, y);
            }
            else {
                // 垂直移动
                e.deltaY < 0 ? this.translate(0, 20) : this.translate(0, -20);
            }
            this.#labelNeedSelect('ing');
            this.#drawPipeLine();
            this.#drawLocation();
        });
        cvs.addEventListener('mouseover', (e) => {
            saveMouseP(e);
        });
        cvs.addEventListener('mousemove', (e) => {
            saveMouseP(e);
            this.#labelNeedSelect('ing');
            this.#addDrawing('mousemove');
            this.#selectLabelPoint();
            this.#moveLabelPoint();
            this.#moveSelectLabel(e.movementX, e.movementY);
            this.#drawMove(e.movementX, e.movementY);
            this.#drawLocation();
        });
        cvs.addEventListener('mouseout', () => {
            // console.log('mout')
            this.#selectIngLabelIds = [];
            this.#drawPipeLine();
        });
        addEventListener('keydown', this.#keyDownEvent.bind(this));
        addEventListener('keyup', this.#keyUpEvent.bind(this));
        cvs.addEventListener('mousedown', (e) => {
            saveMouseP(e);
            this.#labelNeedSelect('entry');
            this.#store.mouseIsDown = !this.#store.mouseIsDown;
        });
        cvs.addEventListener('click', () => {
            this.#addDrawing('click');
            this.#drawPipeLine();
            this.#drawLocation();
        });
        /* 双击事件 主要用于 提交 闭合 多边形的路径 */
        cvs.addEventListener('dblclick', () => {
            this.#addDrawing('dblclick');
            this.#addDrawingEnd('dblclick');
        });
        /* 鼠标抬起时间 主要用于 提交 闭合 方框路径 */
        cvs.addEventListener('mouseup', (e) => {
            saveMouseP(e);
            this.#addDrawingEnd('mouseup');
            this.#store.mouseIsDown = false;
        });
    }
    /**
     * 键盘按下事件 该事件将被绑定到document
     * @param e 键盘事件对象
     */
    #keyDownEvent(e) {
        if (!this.#canvas) {
            return;
        }
        if (this.#setting.offKbdEvent) {
            return;
        }
        if (e.key === 'Shift' && !e.ctrlKey && !e.altKey) {
            e.preventDefault();
            this.checkOpType(OpType.Move);
        }
        else if (e.key === 'f' || e.key === 'F') {
            e.preventDefault();
            this.checkOpType(CanvasLabelType.BOX);
        }
        else if (e.key === 'd' || e.key === 'D') {
            e.preventDefault();
            this.checkOpType(CanvasLabelType.Polygon);
        }
        else if (e.key === 'q' || e.key === 'Q') {
            e.preventDefault();
            this.checkOpType(OpType.Select);
        }
        else if (e.key === 'a' || e.key === 'A') {
            this.checkOpType(OpType.None);
        }
        this.#drawPipeLine();
        this.#drawLocation();
    }
    /**
     * 键盘弹起事件 该事件将被绑定到document
     * @param e 键盘事件对象
     */
    #keyUpEvent(e) {
        if (!this.#canvas) {
            return;
        }
        // const cvs = this.#canvas
        if (e.key === 'Shift') {
            this.returnOpType();
            this.#drawPipeLine();
            this.#drawLocation();
        }
    }
    /**
     * 添加点数据
     * @param et 事件类型
     */
    #addDrawing(et) {
        if (!this.#backData) {
            return;
        }
        let x = this.#store.cx;
        let y = this.#store.cy;
        let that = this;
        // 生成数据
        function createData(type) {
            let useIds = [];
            that.#setting.labelTypeList?.forEach((data) => {
                if (data.use) {
                    useIds.push(data.id);
                }
            });
            return {
                id: new Date().getTime(),
                /* 数据展开避免浅拷贝影响 */
                labelTypeIds: [...useIds],
                type,
                data: [],
                hidden: false,
                select: false
            };
        }
        // 画框 在鼠标按下的时候 且现在处于画框模式 并且没有可以编辑的点位
        if (this.#store.mouseIsDown && this.#opType === CanvasLabelType.BOX && this.#canEditPoint.length == 0) {
            /* 有数据才能够进行画框 */
            if (this.#labelIngData) {
                let w = x - this.#labelIngData.data[0];
                let h = y - this.#labelIngData.data[1];
                if (this.#labelIngData.data.length === 4) {
                    this.#labelIngData.data.splice(this.#labelIngData.data.length - 2, 2, w, h);
                }
                else {
                    this.#labelIngData.data.push(w, h);
                }
            }
            else {
                let d = createData(CanvasLabelType.BOX);
                d.data.push(x, y);
                this.#labelIngData = d;
            }
            // 画多边形
        }
        else if (this.#opType === CanvasLabelType.Polygon) {
            if (et === 'dblclick') {
                if (this.#labelIngData) {
                    return;
                }
                // 没有数据则初始化数据
                let d = createData(CanvasLabelType.Polygon);
                d.data.push(x, y);
                this.#labelIngData = d;
            }
            else if (et === 'click') {
                if (this.#labelIngData) {
                    // 如果有数据的话就添加
                    this.#labelIngData.data.push(x, y);
                }
            }
            else if (et === 'mousemove') {
                if (this.#labelIngData && this.#labelIngData.data.length > 2) {
                    this.#labelIngData.data.splice(this.#labelIngData.data.length - 2, 2, x, y);
                }
                else if (this.#labelIngData && this.#labelIngData.data.length === 2) {
                    this.#labelIngData.data.push(x, y);
                }
            }
        }
    }
    /**
     * 结束绘制
     * @param et 事件类型
     */
    #addDrawingEnd(et) {
        if (this.#opType === CanvasLabelType.BOX && et === 'mouseup') {
            if (this.#labelIngData) {
                this.#labelList.set(this.#labelIngData.id, this.#labelIngData);
                this.#eventFun({ type: CanvasEventType.NewLabel, data: this.#labelIngData.id });
                // 触发 更改事件
                this.#eventFun({ type: CanvasEventType.Change, data: this.#labelIngData.id });
            }
            this.#labelIngData = null;
        }
        if (this.#opType === CanvasLabelType.Polygon && et === 'dblclick') {
            if (this.#labelIngData && this.#labelIngData.data.length >= 10) {
                // 去除末尾多余数据
                this.#labelIngData.data.splice(this.#labelIngData.data.length - 4, 4);
                this.#labelList.set(this.#labelIngData.id, this.#labelIngData);
                this.#eventFun({ type: CanvasEventType.NewLabel, data: this.#labelIngData.id });
                // 触发 更改事件
                this.#eventFun({ type: CanvasEventType.Change, data: this.#labelIngData.id });
                this.#labelIngData = null;
            }
        }
    }
    /**
     * 添加标注数据
     * @param data
     */
    addLabel(data) {
        if (Array.isArray(data)) {
            data.forEach((d) => {
                this.#labelList.set(d.id, d);
            });
        }
        else {
            this.#labelList.set(data.id, data);
        }
        this.#drawPipeLine();
    }
    /**
     * 获取所有的标签
     */
    getLabelList() {
        return this.#labelList;
    }
    /**
     * 设置标签数据
     * @param ls 标签数组
     */
    setLabelList(ls) {
        if (ls instanceof Map) {
            this.#labelList = ls;
            this.#drawPipeLine();
        }
        else {
            throw new Error('setLabelList prama must be Map');
        }
    }
    /**
     * 检查现在的操作类型
     * @returns 操作类型
     */
    getOpType() {
        return this.#opType;
    }
    /**
     * 获取背景图片
     * @returns 图片信息
     */
    getback() {
        return this.#backData;
    }
    /**
     * 获取对应标签id 的信息
     * @param ids 标签id列表
     */
    #getLabelSetting(ids) {
        let r = [];
        if (!this.#setting?.labelTypeList) {
            return r;
        }
        let ll = this.#setting.labelTypeList;
        for (let id of ids) {
            if (!ll.has(id)) {
                break;
            }
            r.push(ll.get(id));
        }
        return r;
    }
    /**
     * 查询框 是否拥有某标签类型
     * @param lid 标签id
     * @param tid 类型id
     * @returns
     */
    labelHasType(lid, tid) {
        let label = this.#labelList.get(lid);
        if (!label) {
            return false;
        }
        return label.labelTypeIds.includes(tid);
    }
    /**
     * 修改 标签 所使用的label type
     * @param lid
     * @param tid
     */
    checkLabelType(lid, tid) {
        let label = this.#labelList.get(lid);
        if (!label) {
            return;
        }
        let index = label.labelTypeIds.indexOf(tid);
        if (index >= 0) {
            label.labelTypeIds.splice(index, 1);
            this.#drawPipeLine();
            this.#eventFun({ type: CanvasEventType.Change, data: null });
        }
        else {
            label.labelTypeIds.push(tid);
            this.#drawPipeLine();
            this.#eventFun({ type: CanvasEventType.Change, data: null });
        }
    }
    /**
     * 切换操作类型
     * @param type 需要切换的操作类型
     * @returns
     */
    checkOpType(type) {
        if (!this.#canvas) {
            return;
        }
        const cvs = this.#canvas;
        if (this.#opType !== type) {
            this.#store.oldOpType = this.#opType;
            if (type !== OpType.Move) {
                this.#labelIngData = null;
            }
            this.#opType = type;
            this.#selectIngLabelIds = [];
            this.#canEditPoint = [];
            // 如果要画框 或是 之前是选择 就清楚所有选择
            if (type === CanvasLabelType.BOX || type === CanvasLabelType.Polygon || this.#store.oldOpType !== OpType.Select) {
                this.clearSelect();
            }
            if (this.#opType === OpType.Move) {
                cvs.style.cursor = 'grab';
            }
            else {
                cvs.style.cursor = 'none';
            }
            this.#eventFun({ type: CanvasEventType.CheckType, data: this.#opType });
        }
    }
    /**
     * 回退操作类型
     * @returns
     */
    returnOpType() {
        if (!this.#canvas) {
            return;
        }
        const cvs = this.#canvas;
        this.#opType = this.#store.oldOpType;
        if (this.#opType === 'move') {
            cvs.style.cursor = 'grab';
        }
        else {
            cvs.style.cursor = 'none';
        }
        this.#eventFun({ type: CanvasEventType.CheckType, data: this.#opType });
    }
    /**
     * 缩放图片
     * @param s 添加倍数
     * @param x 相对于图片X轴坐标缩放
     * @param y 相对于图片Y轴坐标缩放
     * @returns
     */
    scale(s, x, y) {
        if (!this.#backData || !this.#canvas) {
            return;
        }
        let oz = this.#backData.zoom;
        // 若是缩小的时候 缩放比例 已经很小 就不缩小
        if (s < 0 && oz + s < 0.1) {
            this.#drawPipeLine();
            return;
        }
        if (x === undefined || y === undefined) {
            x = this.#canvas.width / 2;
            y = this.#canvas.height / 2;
        }
        // 计算缩放位置 并且以鼠标为中心缩放
        let nz = (this.#backData.zoom += s);
        let mx = this.#backData.mx;
        let my = this.#backData.my;
        this.#backData.mx = mx - ((x - mx) * (nz / oz) - (x - mx));
        this.#backData.my = my - ((y - my) * (nz / oz) - (y - my));
        this.#eventFun({ type: CanvasEventType.Scale, data: copyBD(this.#backData) });
        this.#drawPipeLine();
    }
    /**
     * 移动图像
     * @param x 水平
     * @param y 垂直
     */
    translate(x = 0, y = 0) {
        if (!this.#backData) {
            return;
        }
        this.#backData.my += y;
        this.#backData.mx += x;
        this.#eventFun({ type: CanvasEventType.Translate, data: copyBD(this.#backData) });
        this.#drawPipeLine();
    }
    /**
     * 绘制背景图
     */
    drawImage(entry) {
        return new Promise((res, rej) => {
            // 清楚旧数据
            this.#backData = null;
            this.#labelList = new Map();
            const setdata = (d) => {
                if (!this.#canvas) {
                    return;
                }
                // 初始化缩放比例 图片位置 图片大小 图片数据
                let data = { mx: 0, my: 0, w: d.width, h: d.height, data: d, zoom: 1 };
                // 计算 高宽 比例
                let hz = this.#canvas.height / data.h;
                let wz = this.#canvas.width / data.w;
                // 缩放比例保持在 图片始终 放在最中间
                data.zoom = (hz < wz ? hz : wz) - 0.05;
                // 设置 图片x坐标
                data.mx = (this.#canvas.width - data.zoom * data.w) / 2;
                // 设置图片y坐标
                data.my = (this.#canvas.height - data.zoom * data.h) / 2;
                // 背景图设置
                this.#backData = data;
                // 清楚画布
                this.clear();
                // 渲染管线
                this.#drawPipeLine();
                this.#eventFun({ type: CanvasEventType.Scale, data: copyBD(this.#backData) });
                res(null);
            };
            // 判断 传入类型
            if (entry instanceof Image) {
                if (entry.complete) {
                    createImageBitmap(entry).then((bm) => {
                        setdata(bm);
                    });
                }
                else {
                    entry.onload = async () => {
                        let bm = await createImageBitmap(entry);
                        setdata(bm);
                    };
                    entry.onerror = () => {
                        rej();
                    };
                }
            }
            else if (entry instanceof ImageBitmap || entry instanceof ImageData) {
                setdata(entry);
            }
            else if (typeof entry === "string") {
                let img = new Image();
                img.onload = async () => {
                    let bm = await createImageBitmap(img);
                    setdata(bm);
                };
                img.onerror = () => {
                    rej();
                };
                img.src = entry;
            }
        });
    }
    /**
     * 画框
     * @param data 框数据
     * @param fs 填充样式
     * @param ss 描边样式
     */
    #drawBox(d, index) {
        if (!this.#ctx) {
            return;
        }
        let ctx = this.#ctx;
        ctx.save();
        let setting = this.#getLabelSetting(d.labelTypeIds);
        if (setting.length === 0) {
            ctx.restore();
            return;
        } /* 判断是否处于选择状态 */
        if (d.select) {
            ctx.fillStyle = this.#setting.selectStyle?.fillStyle;
            ctx.strokeStyle = this.#setting.selectStyle?.strokeStyle;
            ctx.lineWidth = this.#setting.selectStyle?.strokeWidth;
            // 判断是否出去选择中
        }
        else if (this.#selectIngLabelIds.indexOf(d.id) >= 0) {
            ctx.fillStyle = this.#setting.selectIngStyle?.fillStyle;
            ctx.strokeStyle = this.#setting.selectIngStyle?.strokeStyle;
            ctx.lineWidth = this.#setting.selectIngStyle?.strokeWidth;
            // 使用正常的样式
        }
        else {
            ctx.fillStyle = setting?.[0].fillStyle || '#0008';
            ctx.strokeStyle = setting?.[0].strokeStyle || '#000';
            ctx.lineWidth = setting?.[0].strokeWidth || 2;
        }
        ctx.lineCap = 'round';
        ctx.lineJoin = "round";
        ctx.fillRect(d.data[0], d.data[1], d.data[2], d.data[3]);
        ctx.strokeRect(d.data[0], d.data[1], d.data[2], d.data[3]);
        ctx.fillStyle = setting?.[0].fontFillStyle || '#0008';
        ctx.font = setting?.[0].font || "15px '微软雅黑'";
        ctx.textAlign = 'center';
        let tag = '';
        if (this.#setting.showLabelTagType === 'name') {
            setting.forEach((st) => {
                tag += st.name + " ";
            });
        }
        else if (this.#setting.showLabelTagType === 'number') {
            tag = index.toString();
        }
        else if (this.#setting.showLabelTagType === 'id') {
            tag = d.id?.toString() || '无id';
        }
        // 去除两边空白
        tag = tag.trim();
        ctx.fillText(tag || '未定义标签', (d.data[0] + d.data[0] + d.data[2]) / 2, d.data[1] - 5);
        ctx.restore();
        // 绘制被选中的框的所有点
        if (d.select) {
            let l = getLabelData(d);
            for (let i = 0; i < l.length / 2; i++) {
                this.#dpi(ctx, l[i * 2], l[(i * 2) + 1], (this.#setting.selectIngStyle?.strokeWidth || 6) / 2);
            }
        }
    }
    /**
     * 绘制路径 但不填充 不描边 渲染
     * @param ctx 2d 上下文
     * @param d 点数据
     */
    #dp(ctx, d) {
        ctx.beginPath();
        let l = d.data.length / 2;
        let minx = 0;
        let miny = 0;
        let maxx = 0;
        // 上方数据用来 求出 框的 上方中心位置
        for (let i = 0; i < l; i++) {
            if (i == 0) {
                ctx.moveTo(d.data[0], d.data[1]);
                maxx = minx = d.data[0];
                miny = d.data[1];
            }
            else {
                let ai = i * 2;
                if (d.data[ai] < minx) {
                    minx = d.data[ai];
                }
                else if (d.data[ai] > maxx) {
                    maxx = d.data[ai];
                }
                if (d.data[ai + 1] < miny) {
                    miny = d.data[ai + 1];
                }
                ctx.lineTo(d.data[ai], d.data[ai + 1]);
            }
        }
        ctx.closePath();
        return { minx, miny, maxx };
    }
    /**
     *
     * @param d 绘制参数
     * @param index
     * @returns
     */
    #drawPath(d, index) {
        if (!this.#ctx) {
            return;
        }
        let ctx = this.#ctx;
        ctx.save();
        let st = this.#getLabelSetting(d.labelTypeIds);
        if (st.length === 0) {
            ctx.restore();
            return;
        }
        // 绘制路径不渲染
        let { minx, miny, maxx } = this.#dp(ctx, d);
        // 加载设置
        if (this.#selectLabelIds.indexOf(d.id) >= 0) {
            ctx.fillStyle = this.#setting.selectStyle?.fillStyle || '#0008';
            ctx.strokeStyle = this.#setting.selectStyle?.strokeStyle || '#000';
            ctx.lineWidth = this.#setting.selectStyle?.strokeWidth || 6;
        }
        else if (this.#selectIngLabelIds.indexOf(d.id) >= 0) {
            ctx.fillStyle = this.#setting.selectIngStyle?.fillStyle || '#0008';
            ctx.strokeStyle = this.#setting.selectIngStyle?.strokeStyle || '#000';
            ctx.lineWidth = this.#setting.selectIngStyle?.strokeWidth || 6;
        }
        else {
            ctx.fillStyle = st?.[0].fillStyle || '#0008';
            ctx.strokeStyle = st?.[0].strokeStyle || '#000';
            ctx.lineWidth = st?.[0].strokeWidth || 2;
        }
        ctx.lineCap = 'round';
        ctx.lineJoin = "round";
        ctx.stroke();
        ctx.fill();
        ctx.fillStyle = st?.[0].fontFillStyle || '#0008';
        ctx.font = st?.[0].font || "15px '微软雅黑'";
        ctx.textAlign = 'center';
        let tag = "";
        if (this.#setting.showLabelTagType === 'name') {
            st.forEach((s) => {
                tag += s.name + " ";
            });
        }
        else if (this.#setting.showLabelTagType === 'number') {
            tag = index.toString();
        }
        else if (this.#setting.showLabelTagType === 'id') {
            tag = d.id?.toString() || '无id';
        }
        tag = tag.trim();
        ctx.fillText(tag || '未定义标签', (maxx + minx) / 2, miny - 5);
        ctx.restore();
        // 绘制被选中的框的所有点
        if (d.select) {
            let l = getLabelData(d);
            for (let i = 0; i < l.length / 2; i++) {
                this.#dpi(ctx, l[i * 2], l[(i * 2) + 1], this.#setting.selectIngStyle?.strokeWidth / 2);
            }
        }
    }
    /**
     * 绘制点位 作用是在某个坐标上 绘制一个 半径为r 的圆
     * @returns
     */
    #dpi(ctx, x, y, r) {
        ctx.save();
        ctx.beginPath();
        ctx.arc(x, y, r, 0, 2 * Math.PI);
        ctx.fillStyle = this.#setting.selectStyle?.pointFillStyle || 'black';
        ctx.fill();
        ctx.closePath();
        ctx.restore();
    }
    /**
     *
     * 绘制 当前处于编辑状态的点位
     */
    #drawPoint() {
        if (!this.#ctx || !this.#backData) {
            return;
        }
        if (this.#canEditPoint.length === 0) {
            return;
        }
        let d = this.#backData;
        let ctx = this.#ctx;
        let r = (this.#setting.selectStyle?.pointFillR) / d.zoom;
        if (r < (this.#setting.selectStyle?.pointFillR)) {
            r = this.#setting.selectStyle?.pointFillR;
        }
        let x = this.#canEditPoint[1];
        let y = this.#canEditPoint[2];
        this.#dpi(ctx, x, y, r);
    }
    /**
     * 绘制十字准星
     * @param param
     */
    #drawLocation() {
        if (!this.#canvas || !this.#ctx || this.#opType === 'move') {
            return;
        }
        let x = this.#store.x;
        let y = this.#store.y;
        let cx = this.#store.cx;
        let cy = this.#store.cy;
        const cvs = this.#canvas;
        const ctx = this.#ctx;
        ctx.save();
        ctx.lineWidth = this.#setting?.sightBead?.coordinatesWidth;
        ctx.strokeStyle = this.#setting?.sightBead?.coordinatesColor;
        ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, cvs.height);
        ctx.closePath();
        ctx.moveTo(0, y);
        ctx.lineTo(cvs.width, y);
        // 准心线条颜色相反
        ctx.globalCompositeOperation = 'difference';
        ctx.stroke();
        ctx.restore();
        ctx.save();
        ctx.font = this.#setting?.sightBead?.fontStyle;
        ctx.fillStyle = this.#setting?.sightBead?.fontColor;
        ctx.textAlign = 'center';
        // 准心坐标文字颜色相反
        ctx.globalCompositeOperation = 'difference';
        // 绘制坐标文本
        ctx.fillText(`x = ${cx.toFixed(2)}px , y = ${cy.toFixed(2)}px`, x - 100, y - 8);
        ctx.fillText(`x = ${cx.toFixed(2)}px , y = ${cy.toFixed(2)}px`, x + 100, y - 8);
        ctx.restore();
    }
    /**
     * 移动画布
     * @param x
     * @param y
     */
    #drawMove(x, y) {
        if (this.#opType !== 'move') {
            this.#drawPipeLine();
            return;
        }
        this.translate(x, y);
    }
    /**
     * 绘制标签
     * @param l 绘画数据
     * @param index 数据的index
     * @returns
     */
    #drawLabel(l, index) {
        // 检查是否需要被绘制
        if (this.#labelNeedHidden(l)) {
            return;
        }
        if (l.type === CanvasLabelType.BOX) {
            this.#drawBox(l, index);
        }
        else if (l.type === CanvasLabelType.Polygon) {
            this.#drawPath(l, index);
        }
    }
    /**
     * 检查标签需不需要被隐藏
     * @param l 标签信息
     * @returns
     */
    #labelNeedHidden(l) {
        if (this.labelIsHidden(l.id)) {
            return true;
        }
        for (let id of l.labelTypeIds) {
            if (this.labelTypeIsHidden(id)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 被选择的所有标签 */
    #selectIngLabelIds = [];
    /**
     * 检查路径是否被选择 并且将被选择的id 放入到 选择列表
     * entry 选中 ing 让其处于选择中
     * @returns
     */
    #labelNeedSelect(et) {
        if (this.#labelIngData !== null || !this.#ctx || !this.#backData) {
            return;
        }
        // 检查现在是否在编辑点 如果是的话 就不用进行选择
        if (this.#canEditPoint.length > 0 || this.#store.mouseIsDown) {
            return;
        }
        const ls = Array.from(this.#labelList);
        let ctx = this.#ctx;
        // 保存绘制状态
        ctx.save();
        let back = this.#backData;
        ctx.transform(back.zoom, 0, 0, back.zoom, back.mx, back.my);
        this.#selectIngLabelIds = [];
        for (let i = ls.length - 1; i >= 0; i--) {
            ctx.save();
            if (this.#labelNeedHidden(ls[i][1])) {
                ctx.restore();
                continue;
            }
            // 判断 要绘制什么
            if (ls[i][1].type === CanvasLabelType.BOX) {
                // 绘制矩形 不渲染
                ctx.rect(ls[i][1].data[0], ls[i][1].data[1], ls[i][1].data[2], ls[i][1].data[3]);
            }
            else if (ls[i][1].type === CanvasLabelType.Polygon) {
                // 绘制路径不渲染
                this.#dp(ctx, ls[i][1]);
            }
            // 检查坐标是否在路径内
            if (ctx.isPointInPath(this.#store.x, this.#store.y)) {
                if (et === 'ing') {
                    this.#selectIngLabelIds = [ls[i][0]];
                }
                else if (et === 'entry') {
                    this.selectLabels([ls[i][0]], false);
                }
                // 因为直接 返回函数 所以需要两次 回退状态
                ctx.restore();
                ctx.restore();
                // 找到直接不判断后面的
                return;
            }
            ctx.restore();
        }
        ctx.restore();
    }
    /**
     * 选择某些标签
     * @param ids 需要选中的标签
     * @param d 是否需要进行重绘
     */
    selectLabels(ids, d = true) {
        this.clearSelect();
        this.#selectLabelIds = [...ids];
        for (let id of ids) {
            let label = this.#labelList.get(id);
            if (!label) {
                break;
            }
            label.select = true;
        }
        this.#eventFun({ type: CanvasEventType.Select, data: this.#selectLabelIds });
        if (d) {
            this.#drawPipeLine();
        }
    }
    /**
     * 获取被选择的所有标签ids
     * @returns 所有被选择的id
     */
    getSelectLabels() {
        let labels = [];
        for (let id of this.#selectLabelIds) {
            let label = this.#labelList.get(id);
            if (label) {
                labels.push(label);
            }
        }
        return labels;
    }
    /**
     * 查询标签是否现在处于被选择状态
     * @param id 标签id
     * @returns
     */
    labelIsSelect(id) {
        return this.#selectLabelIds.indexOf(id) >= 0;
    }
    // 正在编辑的点位  索引,x坐标,y坐标
    #canEditPoint = [];
    // 检测鼠标位置是否在某个周围
    #atPointRound(ctx, l, d, draw = false) {
        //  将标签数据取出转换为number[]
        let p = getLabelData(l);
        // 检测半径
        let r = this.#setting.selectStyle?.pointFillR / d.zoom;
        if (r < this.#setting.selectStyle?.pointFillR) {
            r = this.#setting.selectStyle?.pointFillR;
        }
        for (let i = 0; i < p.length / 2; i++) {
            ctx.save();
            ctx.beginPath();
            ctx.arc(p[i * 2], p[(i * 2) + 1], r, 0, 2 * Math.PI);
            ctx.closePath();
            // 检测
            if (ctx.isPointInPath(this.#store.x, this.#store.y)) {
                this.#canEditPoint = [i, p[i * 2], p[i * 2 + 1]];
                this.#selectIngLabelIds = [];
                ctx.restore();
                return i;
            }
            ctx.restore();
        }
        return false;
    }
    /**
     * 选择某个点
     * @returns
     */
    #selectLabelPoint() {
        if (this.#labelIngData !== null || !this.#ctx || !this.#backData) {
            return;
        }
        // 检查现在是否处于多选状态 或无选择 是的话就不能进行点位选择
        if (this.#selectLabelIds.length > 1 || this.#selectLabelIds.length == 0) {
            return;
        }
        if (this.#store.mouseIsDown) {
            return;
        }
        // 重置当前选择的点
        this.#canEditPoint = [];
        for (let l of this.#labelList) {
            if (this.#selectLabelIds[0] === l[0]) {
                if (this.#labelNeedHidden(l[1])) {
                    return;
                }
                let ctx = this.#ctx;
                ctx.save();
                let d = this.#backData;
                ctx.transform(d.zoom, 0, 0, d.zoom, d.mx, d.my);
                this.#atPointRound(ctx, l[1], d);
                ctx.restore();
                return;
            }
        }
    }
    /**
     * 移动正在选择的目标
     * 原生移动标签坐标
     * @param x
     * @param y
     * @returns
     */
    #moveSelectLabel(x, y) {
        if (this.#labelIngData !== null || !this.#ctx || !this.#backData) {
            return;
        }
        // 检查现在是否是在移动点位 有没有被选择的框
        if (!this.#store.mouseIsDown || this.#selectLabelIds.length === 0 || this.#canEditPoint.length > 0) {
            return;
        }
        let b = this.#backData;
        x = x / b.zoom;
        y = y / b.zoom;
        this.moveSelectLabels(x, y, false);
    }
    /**
     * 移动某个标签的某个点
     * @returns
     */
    #moveLabelPoint() {
        if (this.#labelIngData !== null || !this.#ctx || !this.#backData) {
            return;
        }
        if (!this.#store.mouseIsDown) {
            return;
        }
        if (this.#selectLabelIds.length == 1 && this.#canEditPoint.length > 0) {
            this.#labelList.forEach((l) => {
                if (l.id !== this.#selectLabelIds[0]) {
                    return;
                }
                let cx = this.#store.cx;
                let cy = this.#store.cy;
                if (l.type === CanvasLabelType.BOX) {
                    let x = l.data[0];
                    let y = l.data[1];
                    let w = l.data[2];
                    let h = l.data[3];
                    // 根据不同点位调整元数据坐标
                    switch (this.#canEditPoint[0]) {
                        case 0:
                            l.data[0] = cx;
                            l.data[1] = cy;
                            l.data[2] = (x + w) - cx;
                            l.data[3] = (y + h) - cy;
                            break;
                        case 1:
                            l.data[0] = x;
                            l.data[1] = cy;
                            l.data[2] = cx - x;
                            l.data[3] = (y - cy) + h;
                            break;
                        case 2:
                            l.data[0] = x;
                            l.data[1] = y;
                            l.data[2] = cx - x;
                            l.data[3] = cy - y;
                            break;
                        case 3:
                            l.data[0] = cx;
                            l.data[1] = y;
                            l.data[2] = (x - cx) + w;
                            l.data[3] = cy - y;
                            break;
                    }
                }
                else if (l.type === CanvasLabelType.Polygon) {
                    l.data[(this.#canEditPoint[0] * 2)] = cx;
                    l.data[(this.#canEditPoint[0] * 2) + 1] = cy;
                }
                this.#canEditPoint[1] = cx;
                this.#canEditPoint[2] = cy;
            });
            this.#eventFun({ type: CanvasEventType.Change, data: null });
        }
    }
    /**
     * 移动某些标签
     * @param x x 方向移动多少
     * @param y y 方向移动多少
     */
    moveSelectLabels(x = 0, y = 0, o = true) {
        const sLs = this.#selectLabelIds;
        for (let id of sLs) {
            let label = this.#labelList.get(id);
            if (!label) {
                break;
            }
            if (label.type === CanvasLabelType.BOX) {
                label.data[0] = label.data[0] + x;
                label.data[1] = label.data[1] + y;
            }
            else if (label.type === CanvasLabelType.Polygon) {
                let data = [];
                label.data.forEach((d, i) => {
                    if ((i & 1) == 0) {
                        data.push(d + x);
                    }
                    else {
                        data.push(d + y);
                    }
                });
                label.data = data;
            }
        }
        this.#eventFun({ type: CanvasEventType.Change, data: null });
        if (o) {
            this.#drawPipeLine();
        }
    }
    /**
     * 销毁 移除事件绑定
     */
    des() {
        removeEventListener('keydown', this.#keyDownEvent);
        removeEventListener('keyup', this.#keyUpEvent);
        this.offEvent();
        this.#resizeOB?.unobserve(this.#el);
        this.#resizeOB?.disconnect();
    }
    /**
     * 清除筛选
     */
    clearSelect() {
        this.#selectLabelIds = [];
        this.#labelList.forEach((data) => {
            data.select = false;
        });
        this.#eventFun({ type: CanvasEventType.Select, data: this.#selectLabelIds });
    }
}
